// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_ARM64_DECODER_ARM64_H_
#define V8_ARM64_DECODER_ARM64_H_

#include <list>

#include "src/arm64/instructions-arm64.h"
#include "src/globals.h"

namespace v8 {
namespace internal {

    // List macro containing all visitors needed by the decoder class.

#define VISITOR_LIST(V)                   \
    V(PCRelAddressing)                    \
    V(AddSubImmediate)                    \
    V(LogicalImmediate)                   \
    V(MoveWideImmediate)                  \
    V(Bitfield)                           \
    V(Extract)                            \
    V(UnconditionalBranch)                \
    V(UnconditionalBranchToRegister)      \
    V(CompareBranch)                      \
    V(TestBranch)                         \
    V(ConditionalBranch)                  \
    V(System)                             \
    V(Exception)                          \
    V(LoadStorePairPostIndex)             \
    V(LoadStorePairOffset)                \
    V(LoadStorePairPreIndex)              \
    V(LoadLiteral)                        \
    V(LoadStoreUnscaledOffset)            \
    V(LoadStorePostIndex)                 \
    V(LoadStorePreIndex)                  \
    V(LoadStoreRegisterOffset)            \
    V(LoadStoreUnsignedOffset)            \
    V(LoadStoreAcquireRelease)            \
    V(LogicalShifted)                     \
    V(AddSubShifted)                      \
    V(AddSubExtended)                     \
    V(AddSubWithCarry)                    \
    V(ConditionalCompareRegister)         \
    V(ConditionalCompareImmediate)        \
    V(ConditionalSelect)                  \
    V(DataProcessing1Source)              \
    V(DataProcessing2Source)              \
    V(DataProcessing3Source)              \
    V(FPCompare)                          \
    V(FPConditionalCompare)               \
    V(FPConditionalSelect)                \
    V(FPImmediate)                        \
    V(FPDataProcessing1Source)            \
    V(FPDataProcessing2Source)            \
    V(FPDataProcessing3Source)            \
    V(FPIntegerConvert)                   \
    V(FPFixedPointConvert)                \
    V(NEON2RegMisc)                       \
    V(NEON3Different)                     \
    V(NEON3Same)                          \
    V(NEONAcrossLanes)                    \
    V(NEONByIndexedElement)               \
    V(NEONCopy)                           \
    V(NEONExtract)                        \
    V(NEONLoadStoreMultiStruct)           \
    V(NEONLoadStoreMultiStructPostIndex)  \
    V(NEONLoadStoreSingleStruct)          \
    V(NEONLoadStoreSingleStructPostIndex) \
    V(NEONModifiedImmediate)              \
    V(NEONScalar2RegMisc)                 \
    V(NEONScalar3Diff)                    \
    V(NEONScalar3Same)                    \
    V(NEONScalarByIndexedElement)         \
    V(NEONScalarCopy)                     \
    V(NEONScalarPairwise)                 \
    V(NEONScalarShiftImmediate)           \
    V(NEONShiftImmediate)                 \
    V(NEONTable)                          \
    V(NEONPerm)                           \
    V(Unallocated)                        \
    V(Unimplemented)

    // The Visitor interface. Disassembler and simulator (and other tools)
    // must provide implementations for all of these functions.
    class V8_EXPORT_PRIVATE DecoderVisitor {
    public:
        virtual ~DecoderVisitor() { }

#define DECLARE(A) virtual void Visit##A(Instruction* instr) = 0;
        VISITOR_LIST(DECLARE)
#undef DECLARE
    };

    // A visitor that dispatches to a list of visitors.
    class V8_EXPORT_PRIVATE DispatchingDecoderVisitor : public DecoderVisitor {
    public:
        DispatchingDecoderVisitor() { }
        virtual ~DispatchingDecoderVisitor() { }

        // Register a new visitor class with the decoder.
        // Decode() will call the corresponding visitor method from all registered
        // visitor classes when decoding reaches the leaf node of the instruction
        // decode tree.
        // Visitors are called in the order.
        // A visitor can only be registered once.
        // Registering an already registered visitor will update its position.
        //
        //   d.AppendVisitor(V1);
        //   d.AppendVisitor(V2);
        //   d.PrependVisitor(V2);            // Move V2 at the start of the list.
        //   d.InsertVisitorBefore(V3, V2);
        //   d.AppendVisitor(V4);
        //   d.AppendVisitor(V4);             // No effect.
        //
        //   d.Decode(i);
        //
        // will call in order visitor methods in V3, V2, V1, V4.
        void AppendVisitor(DecoderVisitor* visitor);
        V8_EXPORT_PRIVATE void PrependVisitor(DecoderVisitor* visitor);
        void InsertVisitorBefore(DecoderVisitor* new_visitor,
            DecoderVisitor* registered_visitor);
        void InsertVisitorAfter(DecoderVisitor* new_visitor,
            DecoderVisitor* registered_visitor);

        // Remove a previously registered visitor class from the list of visitors
        // stored by the decoder.
        void RemoveVisitor(DecoderVisitor* visitor);

        void VisitNEONShiftImmediate(const Instruction* instr);

#define DECLARE(A) void Visit##A(Instruction* instr);
        VISITOR_LIST(DECLARE)
#undef DECLARE

    private:
        // Visitors are registered in a list.
        std::list<DecoderVisitor*> visitors_;
    };

    template <typename V>
    class Decoder : public V {
    public:
        Decoder() { }
        virtual ~Decoder() { }

        // Top-level instruction decoder function. Decodes an instruction and calls
        // the visitor functions registered with the Decoder class.
        virtual void Decode(Instruction* instr);

    private:
        // Decode the PC relative addressing instruction, and call the corresponding
        // visitors.
        // On entry, instruction bits 27:24 = 0x0.
        void DecodePCRelAddressing(Instruction* instr);

        // Decode the add/subtract immediate instruction, and call the corresponding
        // visitors.
        // On entry, instruction bits 27:24 = 0x1.
        void DecodeAddSubImmediate(Instruction* instr);

        // Decode the branch, system command, and exception generation parts of
        // the instruction tree, and call the corresponding visitors.
        // On entry, instruction bits 27:24 = {0x4, 0x5, 0x6, 0x7}.
        void DecodeBranchSystemException(Instruction* instr);

        // Decode the load and store parts of the instruction tree, and call
        // the corresponding visitors.
        // On entry, instruction bits 27:24 = {0x8, 0x9, 0xC, 0xD}.
        void DecodeLoadStore(Instruction* instr);

        // Decode the logical immediate and move wide immediate parts of the
        // instruction tree, and call the corresponding visitors.
        // On entry, instruction bits 27:24 = 0x2.
        void DecodeLogical(Instruction* instr);

        // Decode the bitfield and extraction parts of the instruction tree,
        // and call the corresponding visitors.
        // On entry, instruction bits 27:24 = 0x3.
        void DecodeBitfieldExtract(Instruction* instr);

        // Decode the data processing parts of the instruction tree, and call the
        // corresponding visitors.
        // On entry, instruction bits 27:24 = {0x1, 0xA, 0xB}.
        void DecodeDataProcessing(Instruction* instr);

        // Decode the floating point parts of the instruction tree, and call the
        // corresponding visitors.
        // On entry, instruction bits 27:24 = {0xE, 0xF}.
        void DecodeFP(Instruction* instr);

        // Decode the Advanced SIMD (NEON) load/store part of the instruction tree,
        // and call the corresponding visitors.
        // On entry, instruction bits 29:25 = 0x6.
        void DecodeNEONLoadStore(Instruction* instr);

        // Decode the Advanced SIMD (NEON) data processing part of the instruction
        // tree, and call the corresponding visitors.
        // On entry, instruction bits 27:25 = 0x7.
        void DecodeNEONVectorDataProcessing(Instruction* instr);

        // Decode the Advanced SIMD (NEON) scalar data processing part of the
        // instruction tree, and call the corresponding visitors.
        // On entry, instruction bits 28:25 = 0xF.
        void DecodeNEONScalarDataProcessing(Instruction* instr);
    };

} // namespace internal
} // namespace v8

#endif // V8_ARM64_DECODER_ARM64_H_
